package umlTool;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.util.Vector;
import org.w3c.dom.*;

/**
 * represents the class
 * 
 * @author Mimo
 *
 */
public class ClassDiagram implements ISaveable, ICommentable {
	Boolean abstractClass, interfaceClass, isExtends, isImplements;
	private String comment;
	private String extend;
	Vector<ClassField> fields;
	Vector<String> implement;
	Vector<ClassMethod> methods;
	private String name;

	public ClassDiagram() {
		fields = new Vector<ClassField>();
		methods = new Vector<ClassMethod>();
		implement = new Vector<String>();
		comment = extend = "";
		abstractClass = interfaceClass = isExtends = isImplements = false;
	}

	public ClassDiagram(Element elem) {
		this();
		name = elem.getAttribute("name");
		NodeList fields = elem.getElementsByTagName("classField");
		for (int i = 0; i < fields.getLength(); i++) {
			this.fields.add(new ClassField((Element) fields.item(i)));
		}
		NodeList methods = elem.getElementsByTagName("classMember");
		for (int i = 0; i < methods.getLength(); i++) {
			this.methods.add(new ClassMethod((Element) methods.item(i)));
		}
	}

	public void addField(ClassField field) {
		fields.add(field);
	}

	/**
	 * adds method to class
	 * 
	 * @param method
	 *            method to be added
	 */
	public void addMethod(ClassMethod method) {
		methods.add(method);
	}

	/**
	 * create the getter for certain field and sets it to private
	 * 
	 * @param index
	 *            put the index of field
	 */
	public void createGetter(int index) {
		fields.get(index).setAccess(AccessModifiers.Private);
		String name = fields.get(index).getName();
		StringBuilder funcName = new StringBuilder("get");
		funcName.append(name);
		funcName.setCharAt(3, Character.toUpperCase(name.charAt(0)));
		ClassMethod m = new ClassMethod(funcName.toString());
		m.setAccess(AccessModifiers.Public);
		m.addParameters(new MethodParameter(name, fields.get(index).getType()));
		m.setImplementation("\treturn " + fields.get(index).getName() + ";");
		m.setType(fields.get(index).getType());
		methods.add(m);
	}

	/**
	 * create the getter for certain field and sets it to private
	 * 
	 * @param index
	 *            put the index of field
	 */
	public void createSetter(int index) {
		fields.get(index).setAccess(AccessModifiers.Private);
		String name = fields.get(index).getName();
		StringBuilder funcName = new StringBuilder("set");
		funcName.append(name);
		funcName.setCharAt(3, Character.toUpperCase(name.charAt(0)));
		ClassMethod m = new ClassMethod(funcName.toString());
		m.setAccess(AccessModifiers.Public);
		m.addParameters(new MethodParameter(name, fields.get(index).getType()));
		m.setImplementation("\tthis." + fields.get(index).getName() + " = "
				+ name + ";");
		m.setType("void");
		methods.add(m);
	}

	@Override
	public String getComment() {
		return comment;
	}

	String getExtend() {
		return extend;
	}

	public Vector<ClassField> getFields() {
		return fields;
	}

	public Vector<ClassMethod> getMethods() {
		return methods;
	}

	String getName() {
		return name;
	}

	/**
	 * saves the class to file in the path
	 * 
	 * @param path
	 *            the pass to save the file into
	 */
	public void saveToFile(String path) {
		StringBuilder content = new StringBuilder();
		content.append(AccessModifiers.Public.toString());
		content.setCharAt(0, 'p');
		if (abstractClass)
			content.append("abstract ");
		if (interfaceClass)
			content.append(" interface ");
		else
			content.append(" class ");
		content.append(name + " ");
		if (isExtends)
			content.append("extends " + extend + " ");
		if (isImplements) {
			content.append(" implements ");
			for (String i : implement) {
				content.append(i + ", ");
			}
			content.setCharAt(content.lastIndexOf(","), ' ');
		}
		content.append("{\n");
		for (ClassField f : fields) {
			content.append(f.toString());
		}
		for (ClassMethod m : methods) {
			content.append(m.toString());
		}
		try {
			FileWriter f = new FileWriter(path);
			BufferedWriter b = new BufferedWriter(f);
			b.write(content.toString());
			b.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	@Override
	public Element saveToXml(Document d) {
		Element elem = d.createElement("classDiagram");
		elem.setAttribute("name", name);
		if (isExtends)
			elem.setAttribute("extend", extend);
		Element f = d.createElement("fields");
		for (ClassField field : fields) {
			f.appendChild(field.saveToXml(d));
		}
		elem.appendChild(f);

		Element m = d.createElement("methods");
		for (ClassMethod method : methods) {
			m.appendChild(method.saveToXml(d));
		}
		elem.appendChild(m);

		return elem;
	}

	@Override
	public void setComment(String comment) {
		this.comment = comment;
	}

	void setExtend(String extend) {
		isExtends = true;
		this.extend = extend;
	}

	public void setName(String name) {
		this.name = name;
	}
}
